home *** CD-ROM | disk | FTP | other *** search
/ Aminet 35 / Aminet 35 (2000)(Schatztruhe)[!][Feb 2000].iso / Aminet / game / shoot / ADescentSrc.lha / descent / main / physics.c < prev    next >
C/C++ Source or Header  |  1998-03-22  |  28KB  |  1,018 lines

  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  12. */
  13. /*                                        
  14.  * $Source: /usr/CVS/descent/main/physics.c,v $
  15.  * $Revision: 1.2 $
  16.  * $Author: tfrieden $
  17.  * $Date: 1998/03/22 15:26:27 $
  18.  * 
  19.  * Code for flying through the mines
  20.  * 
  21.  * $Log: physics.c,v $
  22.  * Revision 1.2  1998/03/22 15:26:27  tfrieden
  23.  * removed lots of warning messages
  24.  *
  25.  * Revision 1.1.1.1  1998/03/03 15:12:28  nobody
  26.  * reimport after crash from backup
  27.  *
  28.  * Revision 1.1.1.1  1998/02/13  20:21:03  hfrieden
  29.  * Initial Import
  30.  */
  31.  
  32. #pragma off (unreferenced)
  33. static char rcsid[] = "$Id: physics.c,v 1.2 1998/03/22 15:26:27 tfrieden Exp $";
  34. #pragma on (unreferenced)
  35.  
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38.  
  39. #include "joy.h"
  40. #include "mono.h"
  41. #include "error.h"
  42.  
  43. #include "inferno.h"
  44. #include "segment.h"
  45. #include "object.h"
  46. #include "physics.h"
  47. #include "key.h"
  48. #include "game.h"
  49. #include "collide.h"
  50. #include "fvi.h"
  51. #include "newdemo.h"
  52. #include "timer.h"
  53. #include "ai.h"
  54. #include "wall.h"
  55. #include "laser.h"
  56.  
  57. //Global variables for physics system
  58.  
  59. #define ROLL_RATE       0x2000
  60. #define DAMP_ANG            0x400                  //min angle to bank
  61.  
  62. #define TURNROLL_SCALE  (0x4ec4/2)
  63.  
  64. #define BUMP_HACK   1       //if defined, bump player when he gets stuck
  65.  
  66. //--unused-- int mike_mode=0;
  67.  
  68. //check point against each side of segment. return bitmask, where bit
  69. //set means behind that side
  70.  
  71. int Physics_cheat_flag = 0;
  72.  
  73. int floor_levelling=0;
  74.  
  75.  
  76. //make sure matrix is orthogonal
  77. check_and_fix_matrix(vms_matrix *m)
  78. {
  79.     vms_matrix tempm;
  80.  
  81.     vm_vector_2_matrix(&tempm,&m->fvec,&m->uvec,NULL);
  82.     *m  = tempm;
  83. }
  84.  
  85.  
  86. void do_physics_align_object( object * obj )
  87. {
  88.     vms_vector desired_upvec;
  89.     fixang delta_ang,roll_ang;
  90.     //vms_vector forvec = {0,0,f1_0};
  91.     vms_matrix temp_matrix;
  92.     fix d,largest_d=-f1_0;
  93.     int i,best_side;
  94.  
  95.  
  96.     // bank player according to segment orientation
  97.  
  98.     //find side of segment that player is most alligned with
  99.  
  100.     for (i=0;i<6;i++) {
  101.         #ifdef COMPACT_SEGS
  102.             vms_vector _tv1;
  103.             get_side_normal( &Segments[obj->segnum], i, 0, &_tv1 );
  104.             d = vm_vec_dot(&_tv1,&obj->orient.uvec);
  105.         #else                   
  106.             d = vm_vec_dot(&Segments[obj->segnum].sides[i].normals[0],&obj->orient.uvec);
  107.         #endif
  108.  
  109.         if (d > largest_d) {largest_d = d; best_side=i;}
  110.     }
  111.  
  112.     if (floor_levelling) {
  113.  
  114.         // old way: used floor's normal as upvec
  115.         #ifdef COMPACT_SEGS
  116.             get_side_normal(&Segments[obj->segnum], 3, 0, &desired_upvec );         
  117.         #else
  118.             desired_upvec = Segments[obj->segnum].sides[3].normals[0];
  119.         #endif
  120.  
  121.     }
  122.     else  // new player leveling code: use normal of side closest to our up vec
  123.         if (get_num_faces(&Segments[obj->segnum].sides[best_side])==2) {
  124.             #ifdef COMPACT_SEGS
  125.                 vms_vector normals[2];
  126.                 get_side_normals(&Segments[obj->segnum], best_side, &normals[0], &normals[1] );         
  127.  
  128.                 desired_upvec.x = (normals[0].x + normals[1].x) / 2;
  129.                 desired_upvec.y = (normals[0].y + normals[1].y) / 2;
  130.                 desired_upvec.z = (normals[0].z + normals[1].z) / 2;
  131.  
  132.                 vm_vec_normalize(&desired_upvec);
  133.             #else
  134.                 side *s = &Segments[obj->segnum].sides[best_side];
  135.                 desired_upvec.x = (s->normals[0].x + s->normals[1].x) / 2;
  136.                 desired_upvec.y = (s->normals[0].y + s->normals[1].y) / 2;
  137.                 desired_upvec.z = (s->normals[0].z + s->normals[1].z) / 2;
  138.         
  139.                 vm_vec_normalize(&desired_upvec);
  140.             #endif
  141.         }
  142.         else
  143.             #ifdef COMPACT_SEGS
  144.                 get_side_normal(&Segments[obj->segnum], best_side, 0, &desired_upvec );         
  145.             #else
  146.                 desired_upvec = Segments[obj->segnum].sides[best_side].normals[0];
  147.             #endif
  148.  
  149.     if (labs(vm_vec_dot(&desired_upvec,&obj->orient.fvec)) < f1_0/2) {
  150.         fixang save_delta_ang;
  151.         vms_angvec tangles;
  152.         
  153.         vm_vector_2_matrix(&temp_matrix,&obj->orient.fvec,&desired_upvec,NULL);
  154.  
  155.         save_delta_ang = delta_ang = vm_vec_delta_ang(&obj->orient.uvec,&temp_matrix.uvec,&obj->orient.fvec);
  156.  
  157.         delta_ang += obj->mtype.phys_info.turnroll;
  158.  
  159.         if (abs(delta_ang) > DAMP_ANG) {
  160.             vms_matrix rotmat, new_pm;
  161.  
  162.             roll_ang = fixmul(FrameTime,ROLL_RATE);
  163.  
  164.             if (abs(delta_ang) < roll_ang) roll_ang = delta_ang;
  165.             else if (delta_ang<0) roll_ang = -roll_ang;
  166.  
  167.             tangles.p = tangles.h = 0;  tangles.b = roll_ang;
  168.             vm_angles_2_matrix(&rotmat,&tangles);
  169.  
  170.             vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat);
  171.             obj->orient = new_pm;
  172.         }
  173.         else floor_levelling=0;
  174.     }
  175.  
  176. }
  177.  
  178. set_object_turnroll(object *obj)
  179. {
  180.     fixang desired_bank;
  181.  
  182.     desired_bank = -fixmul(obj->mtype.phys_info.rotvel.y,TURNROLL_SCALE);
  183.  
  184.     if (obj->mtype.phys_info.turnroll != desired_bank) {
  185.         fixang delta_ang,max_roll;
  186.  
  187.         max_roll = fixmul(ROLL_RATE,FrameTime);
  188.  
  189.         delta_ang = desired_bank - obj->mtype.phys_info.turnroll;
  190.  
  191.         if (labs(delta_ang) < max_roll)
  192.             max_roll = delta_ang;
  193.         else
  194.             if (delta_ang < 0)
  195.                 max_roll = -max_roll;
  196.  
  197.         obj->mtype.phys_info.turnroll += max_roll;
  198.     }
  199.  
  200. }
  201.  
  202. //list of segments went through
  203. int phys_seglist[MAX_FVI_SEGS],n_phys_segs;
  204.  
  205.  
  206. #define MAX_IGNORE_OBJS 100
  207.  
  208. #ifndef NDEBUG
  209. #define EXTRA_DEBUG 1       //no extra debug when NDEBUG is on
  210. #endif
  211.  
  212. #ifdef EXTRA_DEBUG
  213. object *debug_obj=NULL;
  214. #endif
  215.  
  216. #define XYZ(v) (v)->x,(v)->y,(v)->z
  217.  
  218. int Total_retries=0, Total_sims=0;
  219.  
  220. #ifndef NDEBUG
  221. int Dont_move_ai_objects=0;
  222. #endif
  223.  
  224. #define FT (f1_0/64)
  225.  
  226. extern int disable_new_fvi_stuff;
  227. //  -----------------------------------------------------------------------------------------------------------
  228. // add rotational velocity & acceleration
  229. void do_physics_sim_rot(object *obj)
  230. {
  231.     vms_angvec  tangles;
  232.     vms_matrix  rotmat,new_orient;
  233.     //fix           rotdrag_scale;
  234.     physics_info *pi;
  235.  
  236.     Assert(FrameTime > 0);  //Get MATT if hit this!
  237.  
  238.     pi = &obj->mtype.phys_info;
  239.  
  240.     if (!(pi->rotvel.x || pi->rotvel.y || pi->rotvel.z || pi->rotthrust.x || pi->rotthrust.y || pi->rotthrust.z))
  241.         return;
  242.  
  243.     if (obj->mtype.phys_info.drag) {
  244.         int count;
  245.         vms_vector accel;
  246.         fix drag,r,k;
  247.  
  248.         count = FrameTime / FT;
  249.         r = FrameTime % FT;
  250.         k = fixdiv(r,FT);
  251.  
  252.         drag = (obj->mtype.phys_info.drag*5)/2;
  253.  
  254.         if (obj->mtype.phys_info.flags & PF_USES_THRUST) {
  255.  
  256.             vm_vec_copy_scale(&accel,&obj->mtype.phys_info.rotthrust,fixdiv(f1_0,obj->mtype.phys_info.mass));
  257.  
  258.             while (count--) {
  259.  
  260.                 vm_vec_add2(&obj->mtype.phys_info.rotvel,&accel);
  261.  
  262.                 vm_vec_scale(&obj->mtype.phys_info.rotvel,f1_0-drag);
  263.             }
  264.  
  265.             //do linear scale on remaining bit of time
  266.  
  267.             vm_vec_scale_add2(&obj->mtype.phys_info.rotvel,&accel,k);
  268.             vm_vec_scale(&obj->mtype.phys_info.rotvel,f1_0-fixmul(k,drag));
  269.         }
  270.         else {
  271.             fix total_drag=f1_0;
  272.  
  273.             while (count--)
  274.                 total_drag = fixmul(total_drag,f1_0-drag);
  275.  
  276.             //do linear scale on remaining bit of time
  277.  
  278.             total_drag = fixmul(total_drag,f1_0-fixmul(k,drag));
  279.  
  280.             vm_vec_scale(&obj->mtype.phys_info.rotvel,total_drag);
  281.         }
  282.  
  283.     }
  284.  
  285.     //mprintf( (0, "Rot vel = %.3f,%.3f,%.3f\n", f2fl(obj->mtype.phys_info.rotvel.x),f2fl(obj->mtype.phys_info.rotvel.y), f2fl(obj->mtype.phys_info.rotvel.z) ));
  286.  
  287.     //now rotate object 
  288.  
  289.     //unrotate object for bank caused by turn
  290.     if (obj->mtype.phys_info.turnroll) {
  291.         vms_matrix new_pm;
  292.  
  293.         tangles.p = tangles.h = 0;
  294.         tangles.b = -obj->mtype.phys_info.turnroll;
  295.         vm_angles_2_matrix(&rotmat,&tangles);
  296.         vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat);
  297.         obj->orient = new_pm;
  298.     }
  299.   
  300.     tangles.p = fixmul(obj->mtype.phys_info.rotvel.x,FrameTime);
  301.     tangles.h = fixmul(obj->mtype.phys_info.rotvel.y,FrameTime);
  302.     tangles.b  = fixmul(obj->mtype.phys_info.rotvel.z,FrameTime);
  303.  
  304.     vm_angles_2_matrix(&rotmat,&tangles);
  305.     vm_matrix_x_matrix(&new_orient,&obj->orient,&rotmat);
  306.     obj->orient = new_orient;
  307.  
  308.     if (obj->mtype.phys_info.flags & PF_TURNROLL)
  309.         set_object_turnroll(obj);
  310.  
  311.     //re-rotate object for bank caused by turn
  312.     if (obj->mtype.phys_info.turnroll) {
  313.         vms_matrix new_pm;
  314.  
  315.         tangles.p = tangles.h = 0;
  316.         tangles.b = obj->mtype.phys_info.turnroll;
  317.         vm_angles_2_matrix(&rotmat,&tangles);
  318.         vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat);
  319.         obj->orient = new_pm;
  320.     }
  321.  
  322.     check_and_fix_matrix(&obj->orient);
  323. }
  324.  
  325. //  -----------------------------------------------------------------------------------------------------------
  326. //Simulate a physics object for this frame
  327. void do_physics_sim(object *obj)
  328. {
  329.     int ignore_obj_list[MAX_IGNORE_OBJS],n_ignore_objs;
  330.     int iseg;
  331.     int try_again;
  332.     int fate;
  333.     vms_vector frame_vec;           //movement in this frame
  334.     vms_vector new_pos,ipos;        //position after this frame
  335.     int count=0;
  336.     int objnum;
  337.     int WallHitSeg, WallHitSide;
  338.     fvi_info hit_info;
  339.     fvi_query fq;
  340.     vms_vector save_pos;
  341.     int save_seg;
  342.     fix drag;
  343.     fix sim_time;
  344.     vms_vector start_pos;
  345.     int obj_stopped=0;
  346.     fix moved_time;         //how long objected moved before hit something
  347.     vms_vector save_p0,save_p1;
  348.     physics_info *pi;
  349.     int orig_segnum = obj->segnum;
  350.  
  351.     Assert(obj->type != OBJ_NONE);
  352.     Assert(obj->movement_type == MT_PHYSICS);
  353.  
  354. #ifndef NDEBUG
  355. if (Dont_move_ai_objects)
  356.     if (obj->control_type == CT_AI)
  357.         return;
  358. #endif
  359.  
  360.     pi = &obj->mtype.phys_info;
  361.  
  362.     do_physics_sim_rot(obj);
  363.  
  364.     if (!(pi->velocity.x || pi->velocity.y || pi->velocity.z || pi->thrust.x || pi->thrust.y || pi->thrust.z))
  365.         return;
  366.  
  367.     objnum = obj-Objects;
  368.  
  369.     n_phys_segs = 0;
  370.  
  371.     disable_new_fvi_stuff = (obj->type != OBJ_PLAYER);
  372.  
  373.     sim_time = FrameTime;
  374.  
  375. //debug_obj = obj;
  376.  
  377.     #ifdef EXTRA_DEBUG
  378.     if (obj == debug_obj) {
  379.         printf("object %d:\n  start pos = %x %x %x\n",objnum,XYZ(&obj->pos));
  380.         printf("  thrust = %x %x %x\n",XYZ(&obj->mtype.phys_info.thrust));
  381.         printf("  sim_time = %x\n",sim_time);
  382.     }
  383.  
  384.     //check for correct object segment 
  385.     if(!get_seg_masks(&obj->pos,obj->segnum,0).centermask==0) {
  386.         #ifndef NDEBUG
  387.         mprintf((0,"Warning: object %d not in given seg!\n",objnum));
  388.         #endif
  389.         //Int3();  Removed by Rob 10/5/94
  390.         if (!update_object_seg(obj)) {
  391.             #ifndef NDEBUG
  392.             mprintf((0,"Warning: can't find seg for object %d - moving\n",objnum));
  393.             #endif
  394.             if (!(Game_mode & GM_MULTI))
  395.                 Int3();
  396.             compute_segment_center(&obj->pos,&Segments[obj->segnum]);
  397.             obj->pos.x += objnum;
  398.         }
  399.     }
  400.     #endif
  401.  
  402.     start_pos = obj->pos;
  403.  
  404.     n_ignore_objs = 0;
  405.  
  406.     Assert(obj->mtype.phys_info.brakes==0);     //brakes not used anymore?
  407.  
  408.         //if uses thrust, cannot have zero drag
  409.     Assert(!(obj->mtype.phys_info.flags&PF_USES_THRUST) || obj->mtype.phys_info.drag!=0);
  410.  
  411. //mprintf((0,"thrust=%x  speed=%x\n",vm_vec_mag(&obj->mtype.phys_info.thrust),vm_vec_mag(&obj->mtype.phys_info.velocity)));
  412.  
  413.     //do thrust & drag
  414.     
  415.     if ((drag = obj->mtype.phys_info.drag) != 0) {
  416.  
  417.         int count;
  418.         vms_vector accel;
  419.         fix r,k;
  420.  
  421.         count = sim_time / FT;
  422.         r = sim_time % FT;
  423.         k = fixdiv(r,FT);
  424.  
  425.         if (obj->mtype.phys_info.flags & PF_USES_THRUST) {
  426.  
  427.             vm_vec_copy_scale(&accel,&obj->mtype.phys_info.thrust,fixdiv(f1_0,obj->mtype.phys_info.mass));
  428.  
  429.             while (count--) {
  430.  
  431.                 vm_vec_add2(&obj->mtype.phys_info.velocity,&accel);
  432.  
  433.                 vm_vec_scale(&obj->mtype.phys_info.velocity,f1_0-drag);
  434.             }
  435.  
  436.             //do linear scale on remaining bit of time
  437.  
  438.             vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&accel,k);
  439.  
  440.             vm_vec_scale(&obj->mtype.phys_info.velocity,f1_0-fixmul(k,drag));
  441.         }
  442.         else {
  443.             fix total_drag=f1_0;
  444.  
  445.             while (count--)
  446.                 total_drag = fixmul(total_drag,f1_0-drag);
  447.  
  448.             //do linear scale on remaining bit of time
  449.  
  450.             total_drag = fixmul(total_drag,f1_0-fixmul(k,drag));
  451.  
  452.             vm_vec_scale(&obj->mtype.phys_info.velocity,total_drag);
  453.         }
  454.     }
  455.  
  456.     #ifdef EXTRA_DEBUG
  457.     if (obj == debug_obj)
  458.         printf("  velocity = %x %x %x\n",XYZ(&obj->mtype.phys_info.velocity));
  459.     #endif
  460.  
  461.     do {
  462.         try_again = 0;
  463.  
  464.         //Move the object
  465.         vm_vec_copy_scale(&frame_vec, &obj->mtype.phys_info.velocity, sim_time);
  466.  
  467.         #ifdef EXTRA_DEBUG
  468.         if (obj == debug_obj)
  469.             printf("  pass %d, frame_vec = %x %x %x\n",count,XYZ(&frame_vec));
  470.         #endif
  471.  
  472.         if ( (frame_vec.x==0) && (frame_vec.y==0) && (frame_vec.z==0) ) 
  473.             break;
  474.  
  475.         count++;
  476.  
  477.         //  If retry count is getting large, then we are trying to do something stupid.
  478.         if ( count > 3)     {
  479.             if (obj->type == OBJ_PLAYER) {
  480.                 if (count > 8)
  481.                     break;
  482.             } else
  483.                 break;
  484.         }
  485.  
  486.         vm_vec_add(&new_pos,&obj->pos,&frame_vec);
  487.  
  488.         #ifdef EXTRA_DEBUG
  489.         if (obj == debug_obj)
  490.             printf("   desired_pos  = %x %x %x\n",XYZ(&new_pos));
  491.         #endif
  492.  
  493.         ignore_obj_list[n_ignore_objs] = -1;
  494.  
  495.         #ifdef EXTRA_DEBUG
  496.         if (obj == debug_obj) {
  497.             printf("   FVI parms: p0 = %8x %8x %8x, segnum=%x, size=%x\n",XYZ(&obj->pos),obj->segnum,obj->size);
  498.             printf("              p1 = %8x %8x %8x\n",XYZ(&new_pos));
  499.         }
  500.         #endif
  501.  
  502.         fq.p0                       = &obj->pos;
  503.         fq.startseg             = obj->segnum;
  504.         fq.p1                       = &new_pos;
  505.         fq.rad                  = obj->size;
  506.         fq.thisobjnum           = objnum;
  507.         fq.ignore_obj_list  = ignore_obj_list;
  508.         fq.flags                    = FQ_CHECK_OBJS;
  509.  
  510.         if (obj->type == OBJ_WEAPON)
  511.             fq.flags |= FQ_TRANSPOINT;
  512.  
  513.         if (obj->type == OBJ_PLAYER)
  514.             fq.flags |= FQ_GET_SEGLIST;
  515.  
  516. //@@            if (get_seg_masks(&obj->pos,obj->segnum,0).centermask!=0)
  517. //@@                Int3();
  518.  
  519. save_p0 = *fq.p0;
  520. save_p1 = *fq.p1;
  521.  
  522.  
  523.         fate = find_vector_intersection(&fq,&hit_info);
  524.         //  Matt: Mike's hack.
  525.         if (fate == HIT_OBJECT) {
  526.             object  *objp = &Objects[hit_info.hit_object];
  527.  
  528.             if ((objp->type == OBJ_WEAPON) && (objp->id == PROXIMITY_ID))
  529.                 count--;
  530.         }
  531.  
  532.         #ifndef NDEBUG
  533.         if (fate == HIT_BAD_P0) {
  534.             mprintf((0,"Warning: Bad p0 in physics!  Object = %i, type = %i [%s]\n", obj-Objects, obj->type, Object_type_names[obj->type]));
  535.             Int3();
  536.         }
  537.         #endif
  538.  
  539.         if (obj->type == OBJ_PLAYER) {
  540.             int i;
  541.  
  542.             if (n_phys_segs && phys_seglist[n_phys_segs-1]==hit_info.seglist[0])
  543.                 n_phys_segs--;
  544.  
  545.             for (i=0;(i<hit_info.n_segs) && (n_phys_segs<MAX_FVI_SEGS-1);  )
  546.                 phys_seglist[n_phys_segs++] = hit_info.seglist[i++];
  547.         }
  548.  
  549.         #ifdef EXTRA_DEBUG
  550.         if (obj == debug_obj)
  551.             printf("   fate  = %d, hit_pnt = %8x %8x %8x\n",fate,XYZ(&hit_info.hit_pnt));;
  552.         #endif
  553.  
  554.         ipos = hit_info.hit_pnt;
  555.         iseg = hit_info.hit_seg;
  556.         WallHitSide = hit_info.hit_side;
  557.         WallHitSeg = hit_info.hit_side_seg;
  558.  
  559.         if (iseg==-1) {     //some sort of horrible error
  560.             #ifndef NDEBUG
  561.             mprintf((1,"iseg==-1 in physics!  Object = %i, type = %i (%s)\n", obj-Objects, obj->type, Object_type_names[obj->type]));
  562.             #endif
  563.             //Int3();
  564.             //compute_segment_center(&ipos,&Segments[obj->segnum]);
  565.             //ipos.x += objnum;
  566.             //iseg = obj->segnum;
  567.             //fate = HIT_NONE;
  568.             if (obj->type == OBJ_WEAPON)
  569.                 obj->flags |= OF_SHOULD_BE_DEAD;
  570.             break;
  571.         }
  572.  
  573.         Assert(!((fate==HIT_WALL) && ((WallHitSeg == -1) || (WallHitSeg > Highest_segment_index))));
  574.  
  575.         //if(!get_seg_masks(&hit_info.hit_pnt,hit_info.hit_seg,0).centermask==0)
  576.         //  Int3();
  577.  
  578.         save_pos = obj->pos;            //save the object's position
  579.         save_seg = obj->segnum;
  580.  
  581.         // update object's position and segment number
  582.         obj->pos = ipos;
  583.  
  584.         #ifdef EXTRA_DEBUG
  585.         if (obj == debug_obj)
  586.             printf("   new pos = %x %x %x\n",XYZ(&obj->pos));
  587.         #endif
  588.  
  589.         if ( iseg != obj->segnum )
  590.             obj_relink(objnum, iseg );
  591.  
  592.         //if start point not in segment, move object to center of segment
  593.         if (get_seg_masks(&obj->pos,obj->segnum,0).centermask!=0) {
  594.             int n;
  595.  
  596.             if ((n=find_object_seg(obj))==-1) {
  597.                 //Int3();
  598.                 if (obj->type==OBJ_PLAYER && (n=find_point_seg(&obj->last_pos,obj->segnum))!=-1) {
  599.                     obj->pos = obj->last_pos;
  600.                     obj_relink(objnum, n );
  601.                 }
  602.                 else {
  603.                     compute_segment_center(&obj->pos,&Segments[obj->segnum]);
  604.                     obj->pos.x += objnum;
  605.                 }
  606.                 if (obj->type == OBJ_WEAPON)
  607.                     obj->flags |= OF_SHOULD_BE_DEAD;
  608.             }
  609.             return;
  610.         }
  611.  
  612.         //calulate new sim time
  613.         {
  614.             //vms_vector moved_vec;
  615.             vms_vector moved_vec_n;
  616.             fix attempted_dist,actual_dist;
  617.  
  618.             actual_dist = vm_vec_normalized_dir(&moved_vec_n,&obj->pos,&save_pos);
  619.  
  620.             if (fate==HIT_WALL && vm_vec_dot(&moved_vec_n,&frame_vec) < 0) {        //moved backwards
  621.  
  622.                 //don't change position or sim_time
  623.  
  624. //*******                   mprintf((0,"Obj %d moved backwards\n",obj-Objects));
  625.  
  626.                 #ifdef EXTRA_DEBUG
  627.                 if (obj == debug_obj)
  628.                     printf("   Warning: moved backwards!\n");
  629.                 #endif
  630.  
  631.                 obj->pos = save_pos;
  632.         
  633.                 //iseg = obj->segnum;       //don't change segment
  634.  
  635.                 obj_relink(objnum, save_seg );
  636.  
  637.                 moved_time = 0;
  638.             }
  639.             else {
  640.                 fix old_sim_time;
  641.  
  642.                 //if (obj == debug_obj)
  643.                 //  printf("   moved_vec = %x %x %x\n",XYZ(&moved_vec));
  644.             
  645.                 attempted_dist = vm_vec_mag(&frame_vec);
  646.  
  647.                 old_sim_time = sim_time;
  648.  
  649.                 sim_time = fixmuldiv(sim_time,attempted_dist-actual_dist,attempted_dist);
  650.  
  651.                 moved_time = old_sim_time - sim_time;
  652.  
  653.                 if (sim_time < 0 || sim_time>old_sim_time) {
  654.                     #ifndef NDEBUG
  655.                     mprintf((0,"Bogus sim_time = %x, old = %x\n",sim_time,old_sim_time));
  656.                     if (obj == debug_obj)
  657.                         printf("   Bogus sim_time = %x, old = %x, attempted_dist = %x, actual_dist = %x\n",sim_time,old_sim_time,attempted_dist,actual_dist);
  658.                     //Int3(); Removed by Rob
  659.                     #endif
  660.                     sim_time = old_sim_time;
  661.                     //WHY DOES THIS HAPPEN??
  662.  
  663.                     moved_time = 0;
  664.                 }
  665.             }
  666.  
  667.             #ifdef EXTRA_DEBUG
  668.             if (obj == debug_obj)
  669.                 printf("   new sim_time = %x\n",sim_time);
  670.             #endif
  671.  
  672.         }
  673.  
  674.  
  675.         switch( fate )      {
  676.  
  677.             case HIT_WALL:      {
  678.                 vms_vector moved_v;
  679.                 //@@fix total_d,moved_d;
  680.                 fix hit_speed,wall_part;
  681.     
  682.                 // Find hit speed   
  683.  
  684.                 vm_vec_sub(&moved_v,&obj->pos,&save_pos);
  685.  
  686.                 wall_part = vm_vec_dot(&moved_v,&hit_info.hit_wallnorm);
  687.  
  688.                 if (wall_part != 0 && moved_time>0 && (hit_speed=-fixdiv(wall_part,moved_time))>0)
  689.                     collide_object_with_wall( obj, hit_speed, WallHitSeg, WallHitSide, &hit_info.hit_pnt );
  690.                 else
  691.                     scrape_object_on_wall(obj, WallHitSeg, WallHitSide, &hit_info.hit_pnt );
  692.  
  693.                 Assert( WallHitSeg > -1 );              
  694.                 Assert( WallHitSide > -1 );             
  695.  
  696.                 if ( !(obj->flags&OF_SHOULD_BE_DEAD) )  {
  697.  
  698.  
  699.                     Assert(! (obj->mtype.phys_info.flags & PF_STICK && obj->mtype.phys_info.flags & PF_BOUNCE));    //can't be bounce and stick
  700.  
  701.                     if (obj->mtype.phys_info.flags & PF_STICK) {        //stop moving
  702.  
  703.                         // mprintf((0, "Object %i stuck at %i:%i\n", obj-Objects, WallHitSeg, WallHitSide));
  704.                         add_stuck_object(obj, WallHitSeg, WallHitSide);
  705.  
  706.                         vm_vec_zero(&obj->mtype.phys_info.velocity);
  707.                         obj_stopped = 1;
  708.                         try_again = 0;
  709.                     }
  710.                     else {                  // Slide object along wall
  711.  
  712.                         //We're constrained by wall, so subtract wall part from 
  713.                         //velocity vector
  714.  
  715.                         wall_part = vm_vec_dot(&hit_info.hit_wallnorm,&obj->mtype.phys_info.velocity);
  716.  
  717.                         if (obj->mtype.phys_info.flags & PF_BOUNCE)     //bounce off wall
  718.                             wall_part *= 2; //Subtract out wall part twice to achieve bounce
  719.  
  720.                         vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&hit_info.hit_wallnorm,-wall_part);
  721.  
  722.                         #ifdef EXTRA_DEBUG
  723.                         if (obj == debug_obj) {
  724.                             printf("   sliding - wall_norm %x %x %x\n",wall_part,XYZ(&hit_info.hit_wallnorm));
  725.                             printf("   wall_part %x, new velocity = %x %x %x\n",wall_part,XYZ(&obj->mtype.phys_info.velocity));
  726.                         }
  727.                         #endif
  728.  
  729.                         try_again = 1;
  730.                     }
  731.                 }
  732.                 break;
  733.             }
  734.  
  735.             case HIT_OBJECT:        {
  736.                 vms_vector old_vel;
  737.  
  738.                 // Mark the hit object so that on a retry the fvi code
  739.                 // ignores this object.
  740.  
  741.                 Assert(hit_info.hit_object != -1);
  742.  
  743.                 //  Calculcate the hit point between the two objects.
  744.                 {   vms_vector  *ppos0, *ppos1, pos_hit;
  745.                     fix         size0, size1;
  746.                     ppos0 = &Objects[hit_info.hit_object].pos;
  747.                     ppos1 = &obj->pos;
  748.                     size0 = Objects[hit_info.hit_object].size;
  749.                     size1 = obj->size;
  750.                     Assert(size0+size1 != 0);   // Error, both sizes are 0, so how did they collide, anyway?!?
  751.                     //vm_vec_scale(vm_vec_sub(&pos_hit, ppos1, ppos0), fixdiv(size0, size0 + size1));
  752.                     //vm_vec_add2(&pos_hit, ppos0);
  753.                     vm_vec_sub(&pos_hit, ppos1, ppos0);
  754.                     vm_vec_scale_add(&pos_hit,ppos0,&pos_hit,fixdiv(size0, size0 + size1));
  755.  
  756.                     old_vel = obj->mtype.phys_info.velocity;
  757.  
  758.                     collide_two_objects( obj, &Objects[hit_info.hit_object], &pos_hit);
  759.  
  760.                 }
  761.  
  762.                 // Let object continue its movement
  763.                 if ( !(obj->flags&OF_SHOULD_BE_DEAD)  ) {
  764.                     //obj->pos = save_pos;
  765.  
  766.                     if (obj->mtype.phys_info.flags&PF_PERSISTENT || (old_vel.x == obj->mtype.phys_info.velocity.x && old_vel.y == obj->mtype.phys_info.velocity.y && old_vel.z == obj->mtype.phys_info.velocity.z)) {
  767.                         //if (Objects[hit_info.hit_object].type == OBJ_POWERUP)
  768.                             ignore_obj_list[n_ignore_objs++] = hit_info.hit_object;
  769.                         try_again = 1;
  770.                     }
  771.                 }
  772.  
  773.                 break;
  774.             }   
  775.             case HIT_NONE:      
  776.                 break;
  777.  
  778.             #ifndef NDEBUG
  779.             case HIT_BAD_P0:
  780.                 Int3();     // Unexpected collision type: start point not in specified segment.
  781.                 mprintf((0,"Warning: Bad p0 in physics!!!\n"));
  782.                 break;
  783.             default:
  784.                 // Unknown collision type returned from find_vector_intersection!!
  785.                 Int3();
  786.                 break;
  787.             #endif
  788.         }
  789.  
  790.     } while ( try_again );
  791.  
  792.     //  Pass retry count info to AI.
  793.     if (obj->control_type == CT_AI) {
  794.         if (count > 0) {
  795.             Ai_local_info[objnum].retry_count = count-1;
  796.             Total_retries += count-1;
  797.             Total_sims++;
  798.         }
  799.     }
  800.  
  801.     if (! obj_stopped)  {   //Set velocity from actual movement
  802.         vms_vector moved_vec;
  803.         vm_vec_sub(&moved_vec,&obj->pos,&start_pos);
  804.         vm_vec_copy_scale(&obj->mtype.phys_info.velocity,&moved_vec,fixdiv(f1_0,FrameTime));
  805.  
  806.         #ifdef BUMP_HACK
  807.         if (obj==ConsoleObject && (obj->mtype.phys_info.velocity.x==0 && obj->mtype.phys_info.velocity.y==0 && obj->mtype.phys_info.velocity.z==0) &&
  808.               !(obj->mtype.phys_info.thrust.x==0 && obj->mtype.phys_info.thrust.y==0 && obj->mtype.phys_info.thrust.z==0)) {
  809.             vms_vector center,bump_vec;
  810.  
  811.             //bump player a little towards center of segment to unstick
  812.  
  813.             compute_segment_center(¢er,&Segments[obj->segnum]);
  814.             vm_vec_normalized_dir_quick(&bump_vec,¢er,&obj->pos);
  815.             vm_vec_scale_add2(&obj->pos,&bump_vec,obj->size/5);
  816.         }
  817.         #endif
  818.     }
  819.  
  820.     //Assert(check_point_in_seg(&obj->pos,obj->segnum,0).centermask==0);
  821.  
  822.     //if (obj->control_type == CT_FLYING)
  823.     if (obj->mtype.phys_info.flags & PF_LEVELLING)
  824.         do_physics_align_object( obj );
  825.  
  826.  
  827.     //hack to keep player from going through closed doors
  828.     if (obj->type==OBJ_PLAYER && obj->segnum!=orig_segnum && (Physics_cheat_flag!=0xBADA55) ) {
  829.         int sidenum;
  830.  
  831.         sidenum = find_connect_side(&Segments[obj->segnum],&Segments[orig_segnum]);
  832.  
  833.         if (sidenum != -1) {
  834.  
  835.             if (! (WALL_IS_DOORWAY(&Segments[orig_segnum],sidenum) & WID_FLY_FLAG)) {
  836.                 side *s;
  837.                 int vertnum,num_faces,i;
  838.                 fix dist;
  839.                 int vertex_list[6];
  840.  
  841.                 //bump object back
  842.  
  843.                 s = &Segments[orig_segnum].sides[sidenum];
  844.  
  845.                 create_abs_vertex_lists( &num_faces, vertex_list, orig_segnum, sidenum);
  846.  
  847.                 //let's pretend this wall is not triangulated
  848.                 vertnum = vertex_list[0];
  849.                 for (i=1;i<4;i++)
  850.                     if (vertex_list[i] < vertnum)
  851.                         vertnum = vertex_list[i];
  852.  
  853.                 #ifdef COMPACT_SEGS
  854.                     {
  855.                     vms_vector _vn;
  856.                     get_side_normal(&Segments[orig_segnum], sidenum, 0, &_vn );
  857.                     dist = vm_dist_to_plane(&start_pos, &_vn, &Vertices[vertnum]);
  858.                     vm_vec_scale_add(&obj->pos,&start_pos,&_vn,obj->size-dist);
  859.                     }
  860.                 #else
  861.                     dist = vm_dist_to_plane(&start_pos, &s->normals[0], &Vertices[vertnum]);
  862.                     vm_vec_scale_add(&obj->pos,&start_pos,&s->normals[0],obj->size-dist);
  863.                 #endif
  864.                 update_object_seg(obj);
  865.  
  866.             }
  867.         }
  868.     }
  869.  
  870. //--WE ALWYS WANT THIS IN, MATT AND MIKE DECISION ON 12/10/94, TWO MONTHS AFTER FINAL   #ifndef NDEBUG
  871.     //if end point not in segment, move object to last pos, or segment center
  872.     if (get_seg_masks(&obj->pos,obj->segnum,0).centermask!=0) {
  873.         if (find_object_seg(obj)==-1) {
  874.             int n;
  875.  
  876.             //Int3();
  877.             if (obj->type==OBJ_PLAYER && (n=find_point_seg(&obj->last_pos,obj->segnum))!=-1) {
  878.                 obj->pos = obj->last_pos;
  879.                 obj_relink(objnum, n );
  880.             }
  881.             else {
  882.                 compute_segment_center(&obj->pos,&Segments[obj->segnum]);
  883.                 obj->pos.x += objnum;
  884.             }
  885.             if (obj->type == OBJ_WEAPON)
  886.                 obj->flags |= OF_SHOULD_BE_DEAD;
  887.         }
  888.     }
  889. //--WE ALWYS WANT THIS IN, MATT AND MIKE DECISION ON 12/10/94, TWO MONTHS AFTER FINAL   #endif
  890.  
  891.  
  892. }
  893.  
  894.  
  895. //Applies an instantaneous force on an object, resulting in an instantaneous
  896. //change in velocity.
  897. void phys_apply_force(object *obj,vms_vector *force_vec)
  898. {
  899.  
  900.     if (obj->movement_type != MT_PHYSICS)
  901.         return;
  902.  
  903.     //Add in acceleration due to force
  904.     vm_vec_scale_add2(&obj->mtype.phys_info.velocity,force_vec,fixdiv(f1_0,obj->mtype.phys_info.mass));
  905.  
  906.  
  907. }
  908.  
  909. //  ----------------------------------------------------------------
  910. //  Do *dest = *delta unless:
  911. //              *delta is pretty small
  912. //      and they are of different signs.
  913. void physics_set_rotvel_and_saturate(fix *dest, fix delta)
  914. {
  915.     if ((delta ^ *dest) < 0) {
  916.         if (abs(delta) < F1_0/8) {
  917.             // mprintf((0, "D"));
  918.             *dest = delta/4;
  919.         } else
  920.             // mprintf((0, "d"));
  921.             *dest = delta;
  922.     } else {
  923.         // mprintf((0, "!"));
  924.         *dest = delta;
  925.     }
  926. }
  927.  
  928. //  ------------------------------------------------------------------------------------------------------
  929. //  Note: This is the old ai_turn_towards_vector code.
  930. //  phys_apply_rot used to call ai_turn_towards_vector until I fixed it, which broke phys_apply_rot.
  931. void physics_turn_towards_vector(vms_vector *goal_vector, object *obj, fix rate)
  932. {
  933.     vms_angvec  dest_angles, cur_angles;
  934.     fix         delta_p, delta_h;
  935.     vms_vector  *rotvel_ptr = &obj->mtype.phys_info.rotvel;
  936.  
  937.     // Make this object turn towards the goal_vector.  Changes orientation, doesn't change direction of movement.
  938.     // If no one moves, will be facing goal_vector in 1 second.
  939.  
  940.     //  Detect null vector.
  941.     if ((goal_vector->x == 0) && (goal_vector->y == 0) && (goal_vector->z == 0))
  942.         return;
  943.  
  944.     //  Make morph objects turn more slowly.
  945.     if (obj->control_type == CT_MORPH)
  946.         rate *= 2;
  947.  
  948.     vm_extract_angles_vector(&dest_angles, goal_vector);
  949.     vm_extract_angles_vector(&cur_angles, &obj->orient.fvec);
  950.  
  951.     delta_p = (dest_angles.p - cur_angles.p);
  952.     delta_h = (dest_angles.h - cur_angles.h);
  953.  
  954.     if (delta_p > F1_0/2) delta_p = dest_angles.p - cur_angles.p - F1_0;
  955.     if (delta_p < -F1_0/2) delta_p = dest_angles.p - cur_angles.p + F1_0;
  956.     if (delta_h > F1_0/2) delta_h = dest_angles.h - cur_angles.h - F1_0;
  957.     if (delta_h < -F1_0/2) delta_h = dest_angles.h - cur_angles.h + F1_0;
  958.  
  959.     delta_p = fixdiv(delta_p, rate);
  960.     delta_h = fixdiv(delta_h, rate);
  961.  
  962.     if (abs(delta_p) < F1_0/16) delta_p *= 4;
  963.     if (abs(delta_h) < F1_0/16) delta_h *= 4;
  964.  
  965.     physics_set_rotvel_and_saturate(&rotvel_ptr->x, delta_p);
  966.     physics_set_rotvel_and_saturate(&rotvel_ptr->y, delta_h);
  967.     rotvel_ptr->z = 0;
  968. }
  969.  
  970. //  -----------------------------------------------------------------------------
  971. //  Applies an instantaneous whack on an object, resulting in an instantaneous
  972. //  change in orientation.
  973. void phys_apply_rot(object *obj,vms_vector *force_vec)
  974. {
  975.     fix rate, vecmag;
  976.  
  977.     if (obj->movement_type != MT_PHYSICS)
  978.         return;
  979.  
  980.     vecmag = vm_vec_mag(force_vec)/8;
  981.     if (vecmag < F1_0/256)
  982.         rate = 4*F1_0;
  983.     else if (vecmag < obj->mtype.phys_info.mass >> 14)
  984.         rate = 4*F1_0;
  985.     else {
  986.         rate = fixdiv(obj->mtype.phys_info.mass, vecmag);
  987.         if (obj->type == OBJ_ROBOT) {
  988.             if (rate < F1_0/4)
  989.                 rate = F1_0/4;
  990.             obj->ctype.ai_info.SKIP_AI_COUNT = 2;
  991.         } else {
  992.             if (rate < F1_0/2)
  993.                 rate = F1_0/2;
  994.         }
  995.     }
  996.  
  997.     //  Turn amount inversely proportional to mass.  Third parameter is seconds to do 360 turn.
  998.     physics_turn_towards_vector(force_vec, obj, rate);
  999.  
  1000.  
  1001. }
  1002.  
  1003.  
  1004. //this routine will set the thrust for an object to a value that will
  1005. //(hopefully) maintain the object's current velocity
  1006. void set_thrust_from_velocity(object *obj)
  1007. {
  1008.     fix k;
  1009.  
  1010.     Assert(obj->movement_type == MT_PHYSICS);
  1011.  
  1012.     k = fixmuldiv(obj->mtype.phys_info.mass,obj->mtype.phys_info.drag,(f1_0-obj->mtype.phys_info.drag));
  1013.  
  1014.     vm_vec_copy_scale(&obj->mtype.phys_info.thrust,&obj->mtype.phys_info.velocity,k);
  1015.  
  1016. }
  1017.  
  1018.